!-------------------------------------------------------------LICENSE--------------------------------------------------------------!
!                                                                                                                                  !
!The MAP code is written in Fortran language for magnetohydrodynamics (MHD) calculation with the adaptive mesh refinement (AMR)    !
!and Message Passing Interface (MPI) parallelization.                                                                              !
!                                                                                                                                  !
!Copyright (C) 2012                                                                                                                !
!Ronglin Jiang                                                                                                                     !
!rljiang@ssc.net.cn                                                                                                                !
!585 Guoshoujing Road. Pudong, Shanghai, P.R.C. 201203                                                                             !
!                                                                                                                                  !
!This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License         !
!as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.             !
!                                                                                                                                  !
!This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of    !
!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.                        !
!                                                                                                                                  !
!You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software     !
!Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.                                                   !
!                                                                                                                                  !
!-------------------------------------------------------------LICENSE--------------------------------------------------------------!

!==================================================================================================================================|
module parameters
!==================================================================================================================================|

   use mpi
   implicit none

   integer(4), parameter :: unit_check_info = 8
   integer(4), parameter :: unit_datamap = 9
   integer(4), parameter :: unit_par = 10
   integer(4), parameter :: unit_in = 11
   integer(4), parameter :: unit_ro = 12
   integer(4), parameter :: unit_mx = 13
   integer(4), parameter :: unit_my = 14
   integer(4), parameter :: unit_mz = 15
   integer(4), parameter :: unit_bx = 16
   integer(4), parameter :: unit_by = 17
   integer(4), parameter :: unit_bz = 18
   integer(4), parameter :: unit_en = 19
   integer(4), parameter :: unit_x = 21
   integer(4), parameter :: unit_y = 22
   integer(4), parameter :: unit_t = 25
   integer(4), parameter :: unit_nt = 26
   integer(4), parameter :: unit_save_state = 27
   integer(4), parameter :: unit_block = 31
   integer(4), parameter :: unit_input = 41
   integer(4), parameter :: unit_datamap_manage_module = 42
   integer(4), parameter :: tag_int = 10
   integer(4), parameter :: tag_x = 20
   integer(4), parameter :: tag_y = 30
   integer(4), parameter :: tag_var = 40
   integer(4), parameter :: n_blocks_info_send = 3

   integer(4), save :: n_dims
   integer(4), save :: sys
   integer(4), save :: ng
   integer(4), save :: nx_no_bnd
   integer(4), save :: nx_block
   integer(4), save :: ini_block_x
   integer(4), save :: nx_total
   integer(4), save :: nx_total_finest
   integer(4), save :: ny_no_bnd
   integer(4), save :: ny_block
   integer(4), save :: ini_block_y
   integer(4), save :: ny_total
   integer(4), save :: ny_total_finest
   integer(4), save :: ratio
   integer(4), save :: ratio2
   integer(4), save :: n_levels
   integer(4), save :: n_neighs
   integer(4), save :: n_d_l
   integer(4), save :: ini_block_order
   integer(4), save :: ratio_order
   integer(4), save :: n_bnd_interior
   integer(4), save :: reflux_size_x            ! save state variable
   integer(4), save :: reflux_size_y            ! save state variable
   integer(4), save :: shareblock_size_x        ! save state variable
   integer(4), save :: shareblock_size_y        ! save state variable
   integer(4), save :: exchange_size_x          ! save state variable
   integer(4), save :: exchange_size_y          ! save state variable
   integer(4), save :: exchange_size_fix_y      ! save state variable
   integer(4), save :: reflux_size_send_x       ! save state variable
   integer(4), save :: reflux_size_recv_x       ! save state variable
   integer(4), save :: reflux_size_send_y       ! save state variable
   integer(4), save :: reflux_size_recv_y       ! save state variable
   integer(4), save :: shareblock_size_send_x   ! save state variable
   integer(4), save :: shareblock_size_recv_x   ! save state variable
   integer(4), save :: shareblock_size_send_y   ! save state variable
   integer(4), save :: shareblock_size_recv_y   ! save state variable
   integer(4), save :: exchange_size_send_x     ! save state variable
   integer(4), save :: exchange_size_recv_x     ! save state variable
   integer(4), save :: exchange_size_send_y     ! save state variable
   integer(4), save :: exchange_size_recv_y     ! save state variable

   integer(4), save :: scheme
   integer(4), save :: riemann_solver_flag
   integer(4), save :: regrid_iterative_flag
   integer(4), save :: reflux_flag
   integer(4), save :: damping_flag
   integer(4), save :: ini_value_save_flag
   integer(4), save :: div_clean_flag
   integer(4), save :: syn_check_flag
   integer(4), save :: save_state_flag
   integer(4), save :: dn_save_state
   integer(4), save :: load_state_flag
   integer(4), save :: n_load_state
   integer(4), save :: output_real8_flag
   integer(4), save :: interpolation_flag
   integer(4), save :: gravity_reset_flag
   integer(4), save :: fixed_mesh_flag
   integer(4), save :: resistivity_flag
   integer(4), save :: heat_conduction_flag

   real(8), save :: rangex
   real(8), save :: zero_posx
   real(8), save :: rangey
   real(8), save :: zero_posy
   real(8), save :: hc0
   real(8), save :: cd
   real(8), save :: thr_al
   real(8), save :: thr_de
   real(8), save :: thr_ex
   real(8), save :: thr_fl
   real(8), save :: gm
   real(8), save :: gmm1
   real(8), save :: t_end
   real(8), save :: cfl
   real(8), save :: eps
   real(8), save :: pi

   integer(4), dimension(:, :, :), allocatable, save :: bnd_exterior
   integer(4), dimension(:, :, :, :), allocatable, save :: bnd_interior
   real(8), dimension(:, :), allocatable, save :: bnd_interior_pos
   real(8), dimension(:), allocatable, save :: thr_va0

   character(128), save :: directory = ''
   character(128), save :: parameters_filename = 'parameters'
   character(128), save :: datamap_path = ''

   logical(4), save :: ro_total_flag = .true.    ! initial condition
   logical(4), save :: mx_total_flag = .true.    ! initial condition
   logical(4), save :: my_total_flag = .true.    ! initial condition
   logical(4), save :: mz_total_flag = .true.    ! initial condition
   logical(4), save :: bx_total_flag = .true.    ! initial condition
   logical(4), save :: by_total_flag = .true.    ! initial condition
   logical(4), save :: bz_total_flag = .true.    ! initial condition
   logical(4), save :: en_total_flag = .true.    ! initial condition
   logical(4), save :: ro_total_x_flag = .true.    ! initial condition
   logical(4), save :: mx_total_x_flag = .true.    ! initial condition
   logical(4), save :: my_total_x_flag = .true.    ! initial condition
   logical(4), save :: mz_total_x_flag = .true.    ! initial condition
   logical(4), save :: bx_total_x_flag = .true.    ! initial condition
   logical(4), save :: by_total_x_flag = .true.    ! initial condition
   logical(4), save :: bz_total_x_flag = .true.    ! initial condition
   logical(4), save :: en_total_x_flag = .true.    ! initial condition
   logical(4), save :: ro_total_y_flag = .true.    ! initial condition
   logical(4), save :: mx_total_y_flag = .true.    ! initial condition
   logical(4), save :: my_total_y_flag = .true.    ! initial condition
   logical(4), save :: mz_total_y_flag = .true.    ! initial condition
   logical(4), save :: bx_total_y_flag = .true.    ! initial condition
   logical(4), save :: by_total_y_flag = .true.    ! initial condition
   logical(4), save :: bz_total_y_flag = .true.    ! initial condition
   logical(4), save :: en_total_y_flag = .true.    ! initial condition

   integer(4), save :: n_gene
   integer(4), save :: n_int
   integer(4), save :: n_x
   integer(4), save :: n_y
   integer(4), save :: n_thr = 9
   integer(4), save :: error
   integer(4), save :: mpi_status(mpi_status_size)
   integer(4), save :: cpu_number                  ! save state variable
   integer(4), save :: cpu_id
   integer(4), save :: cpu_id_p1
   integer(4), save :: n_blocks_all                ! save state variable
   integer(4), save :: n_blocks_vip_all
   integer(4), save :: max_level = 1               ! save state variable
   integer(4), save :: ns = 1                      ! save state variable
   integer(4), save :: ns_hc = 1
   integer(4), save :: nt = 0                      ! save state variable
   integer(4), save :: n_save_state = 0            ! save state variable

   real(8), save :: max_et = 0.0d0                 ! save state variable
   real(8), save :: max_te_ro = 0.0d0              ! save state variable
   real(8), save :: t_s
   real(8), save :: t_e
   real(8), save :: t                              ! save state variable
   real(8), save :: t_hc
   real(8), save :: t_loop = 0.0d0
   real(8), save :: t_loop_pre = 0.0d0
   real(8), save :: t_remain = 0.0d0
   real(8), save :: t_output = 0.0d0               ! save state variable
   real(8), save :: dt_output = 0.0d0
   real(8), save :: len_regrid = 1.0d30
   real(8), save :: min_dt = 1.0d30                ! save state variable
   real(8), save :: min_dt_hc = 1.0d30             ! save state variable
   real(8), save :: max_speed = 0.0d0              ! save state variable
   real(8), save :: t_regrid = -1.0d0              ! save state variable
   real(8), save :: time_regrid = 0.0d0
   real(8), save :: time_regrid_one = 0.0d0
   real(8), save :: time_integrate = 0.0d0
   real(8), save :: time_integrate_one = 0.0d0
   real(8), save :: time_boundary = 0.0d0
   real(8), save :: time_boundary_one = 0.0d0
   real(8), save :: time_output = 0.0d0
   real(8), save :: time_output_one = 0.0d0
   real(8), save :: time_other = 0.0d0
   real(8), save :: time_other_one = 0.0d0
   real(8), save :: t_loop_s = 0.0d0
   real(8), save :: t_loop_e = 0.0d0

   integer(1), dimension(:), allocatable, save :: blocks_vip_flag
   integer(1), dimension(:), allocatable, save :: blocks_vip_flag_all

   integer(4), dimension(:), allocatable, save :: i_gene
   integer(4), dimension(:, :, :), allocatable, save :: gene
   integer(4), dimension(:), allocatable, save :: n_blocks                                   ! save state variable
   integer(4), dimension(:), allocatable, save :: n_blocks_vip
   integer(4), dimension(:), allocatable, save :: level_len
   integer(4), dimension(:), allocatable, save :: hilbert_start                              ! save state variable
   integer(4), dimension(:), allocatable, save :: hilbert_end                                ! save state variable
   integer(4), dimension(:, :), allocatable, save :: n_blocks_sendrecv                       ! load balance
   integer(4), dimension(:), allocatable, save :: n_blocks_update_send                       ! data update after integrate
   integer(4), dimension(:, :), allocatable, save :: n_blocks_update_sendrecv                ! data update after integrate
   integer(4), dimension(:, :, :, :), allocatable, save :: blocks_update_info_send           ! data update after integrate
   integer(4), dimension(:, :, :, :), allocatable, save :: blocks_update_info_recv           ! data update after integrate
   integer(4), dimension(:, :), allocatable, save :: n_neighs_reflux_sendrecv_x              ! boundary condition    ! save state variable
   integer(4), dimension(:, :), allocatable, save :: n_neighs_reflux_sendrecv_y              ! boundary condition    ! save state variable
   integer(4), dimension(:, :), allocatable, save :: n_neighs_shareblock_sendrecv_x          ! boundary condition    ! save state variable
   integer(4), dimension(:, :), allocatable, save :: n_neighs_shareblock_sendrecv_y          ! boundary condition    ! save state variable
   integer(4), dimension(:, :), allocatable, save :: n_neighs_exchange_sendrecv_x            ! boundary condition    ! save state variable
   integer(4), dimension(:, :), allocatable, save :: n_neighs_exchange_sendrecv_y            ! boundary condition    ! save state variable
   integer(4), dimension(:, :), allocatable, save :: n_neighs_exchange_sendrecv_fix_y        ! boundary condition    ! save state variable
   integer(4), dimension(:, :, :), allocatable, save :: neighs_reflux_info_send_x            ! boundary condition    ! save state variable
   integer(4), dimension(:, :, :), allocatable, save :: neighs_reflux_info_send_y            ! boundary condition    ! save state variable
   integer(4), dimension(:, :, :), allocatable, save :: neighs_reflux_info_recv_x            ! boundary condition
   integer(4), dimension(:, :, :), allocatable, save :: neighs_reflux_info_recv_y            ! boundary condition
   integer(4), dimension(:, :, :), allocatable, save :: neighs_shareblock_info_send_x        ! boundary condition    ! save state variable
   integer(4), dimension(:, :, :), allocatable, save :: neighs_shareblock_info_send_y        ! boundary condition    ! save state variable
   integer(4), dimension(:, :, :), allocatable, save :: neighs_shareblock_info_recv_x        ! boundary condition
   integer(4), dimension(:, :, :), allocatable, save :: neighs_shareblock_info_recv_y        ! boundary condition
   integer(4), dimension(:, :, :), allocatable, save :: neighs_exchange_info_send_x          ! boundary condition    ! save state variable
   integer(4), dimension(:, :, :), allocatable, save :: neighs_exchange_info_send_y          ! boundary condition    ! save state variable
   integer(4), dimension(:, :, :), allocatable, save :: neighs_exchange_info_recv_x          ! boundary condition
   integer(4), dimension(:, :, :), allocatable, save :: neighs_exchange_info_recv_y          ! boundary condition
   integer(4), dimension(:, :, :), allocatable, save :: neighs_exchange_info_send_fix_y      ! boundary condition    ! save state variable
   integer(4), dimension(:, :, :), allocatable, save :: neighs_exchange_info_recv_fix_y      ! boundary condition

   real(8), dimension(:), allocatable, save :: x_total        ! initial condition
   real(8), dimension(:), allocatable, save :: ro_total_x     ! initial condition
   real(8), dimension(:), allocatable, save :: mx_total_x     ! initial condition
   real(8), dimension(:), allocatable, save :: my_total_x     ! initial condition
   real(8), dimension(:), allocatable, save :: mz_total_x     ! initial condition
   real(8), dimension(:), allocatable, save :: bx_total_x     ! initial condition
   real(8), dimension(:), allocatable, save :: by_total_x     ! initial condition
   real(8), dimension(:), allocatable, save :: bz_total_x     ! initial condition
   real(8), dimension(:), allocatable, save :: en_total_x     ! initial condition
   real(8), dimension(:), allocatable, save :: y_total        ! initial condition
   real(8), dimension(:), allocatable, save :: ro_total_y     ! initial condition
   real(8), dimension(:), allocatable, save :: mx_total_y     ! initial condition
   real(8), dimension(:), allocatable, save :: my_total_y     ! initial condition
   real(8), dimension(:), allocatable, save :: mz_total_y     ! initial condition
   real(8), dimension(:), allocatable, save :: bx_total_y     ! initial condition
   real(8), dimension(:), allocatable, save :: by_total_y     ! initial condition
   real(8), dimension(:), allocatable, save :: bz_total_y     ! initial condition
   real(8), dimension(:), allocatable, save :: en_total_y     ! initial condition
   real(8), dimension(:, :), allocatable, save :: ro_total    ! initial condition
   real(8), dimension(:, :), allocatable, save :: mx_total    ! initial condition
   real(8), dimension(:, :), allocatable, save :: my_total    ! initial condition
   real(8), dimension(:, :), allocatable, save :: mz_total    ! initial condition
   real(8), dimension(:, :), allocatable, save :: bx_total    ! initial condition
   real(8), dimension(:, :), allocatable, save :: by_total    ! initial condition
   real(8), dimension(:, :), allocatable, save :: bz_total    ! initial condition
   real(8), dimension(:, :), allocatable, save :: en_total    ! initial condition
   real(8), dimension(:, :, :), allocatable, save :: neighs_reflux_send_x      ! boundary condition
   real(8), dimension(:, :, :), allocatable, save :: neighs_reflux_send_y      ! boundary condition
   real(8), dimension(:, :, :), allocatable, save :: neighs_reflux_recv_x      ! boundary condition
   real(8), dimension(:, :, :), allocatable, save :: neighs_reflux_recv_y      ! boundary condition
   real(8), dimension(:, :, :, :), allocatable, save :: neighs_shareblock_send_x     ! boundary condition
   real(8), dimension(:, :, :, :), allocatable, save :: neighs_shareblock_send_y     ! boundary condition
   real(8), dimension(:, :, :, :), allocatable, save :: neighs_shareblock_recv_x     ! boundary condition
   real(8), dimension(:, :, :, :), allocatable, save :: neighs_shareblock_recv_y     ! boundary condition
   real(8), dimension(:, :, :, :), allocatable, save :: neighs_exchange_send_x      ! boundary condition
   real(8), dimension(:, :, :, :), allocatable, save :: neighs_exchange_send_y      ! boundary condition
   real(8), dimension(:, :, :, :), allocatable, save :: neighs_exchange_recv_x      ! boundary condition
   real(8), dimension(:, :, :, :), allocatable, save :: neighs_exchange_recv_y      ! boundary condition
   real(8), dimension(:, :, :, :), allocatable, save :: neighs_shareblock_send_x_hc      ! boundary condition
   real(8), dimension(:, :, :, :), allocatable, save :: neighs_shareblock_send_y_hc      ! boundary condition
   real(8), dimension(:, :, :, :), allocatable, save :: neighs_shareblock_recv_x_hc      ! boundary condition
   real(8), dimension(:, :, :, :), allocatable, save :: neighs_shareblock_recv_y_hc      ! boundary condition

   real(8), dimension(:, :, :, :), allocatable, save :: neighs_exchange_send_x_hc      ! boundary condition
   real(8), dimension(:, :, :, :), allocatable, save :: neighs_exchange_send_y_hc      ! boundary condition
   real(8), dimension(:, :, :, :), allocatable, save :: neighs_exchange_recv_x_hc      ! boundary condition
   real(8), dimension(:, :, :, :), allocatable, save :: neighs_exchange_recv_y_hc      ! boundary condition

end module parameters
